vlwkaos' digital garden

GraphQL - Schemas and Types

  • 모든 GraphQL 서비스는 query할 수 있는 데이터를 type의 모음으로 정의해야한다.
  • GraphQL 서비스는 아무 언어로나 작성될 수 있다. "GraphQL schema language"를 이용하여 언어와 상관없이 스키마와 소통이 가능하다.
  • GraphQL의 가장 기본적인 컴포넌트 형태는 object 형이다. 단순히 특정 오브젝트에 대해 어떤 데이터를 가져올 수 있을지 정의한다.
# Character는 GraphQL Object 타입이다
type Character {
    # 아래는 Character 타입의 필드이다
    name: String!
    appearsIn: [Episode!]!
}
  • 모든 오브젝트 타입은 하나 이상의 인자를 가질 수 있다:
type Starship {
    id: ID!
    name: String!
    # length는 unit이라는 인자를 받을 수 있음
    length(unit: LengthUnit = METER): Float
}
  • 프로그래밍 언어는 함수가 인자를 가지는 반면 GraphQL에서 인자는 이름에 직접 전달된다

The Query and Mutation types

  • schema있는 대부분의 타입은 일반적인 object타입이다. 그러나 두가지 예외가 있다:
schema {
    query: Query
    mutation: Mutation
}
  • query와 mutation은 GraphQL query의 entry point가 된다.

예를 들어 다음과 같은 query가 있으려면

query {
  hero {
    name
  }
  droid(id: "2000") {
    name
  }
}

GraphQL 서비스에서 다음과 같은 Query 타입이 정의되어있어야 한다.

type Query {
 hero(episode: Episode): Character
 droid(id: ID!): Droid
}

Scalar types

오브젝트는 이름과 필드를 가지지만 그건 결국엔 실질적인 값으로 나타내어져야한다. Scalar type은 쿼리의 끝단이라고도 할 수 있다.

기본적인 Scalar type은 다음과 같다:

  • Int: A signed 32‐bit integer.
  • Float: A signed double-precision floating-point value.
  • String: A UTF‐8 character sequence.
  • Boolean: true or false.
  • ID: 문자열과 형태는 같지만, 사람이 읽을 수 없음을 명시함. 용도는 캐시된 오브젝트를 다시 가져올 때 식별용임.

대부분의 GraphQL서비스에서는 직접 만든 Scalar 타입도 존재한다. 예를 들어

scalar Date

그 후 타입이 어떻게 serliaized, deserialized, validate 되는지는 구현에 따른다.

Enumeration types

Enums는 특정 Scalar 값만 가지도록 제한한 타입이다.

List and Non-Null

type Character {
 name: String!
 appearsIn: [Episode]!
}

리스트의 경우 다음에 유의하자

# 배열이 null이면 안됨
myField: [String]!
# 배열 내의 값이 null이면 안됨
myField: [String!]

Interfaces

추상 타입 정의

interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}

확장

type Human implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  starships: [Starship]
  totalCredits: Int
}

query에서 ...on TYPE { 이렇게

Union types

union끼리 결합은 할 수 없다.

union SearchResult = Human | Droid | Starship

그리고 union 타입에 대한 쿼리 결과를 얻으려면 inline fragment를 사용해야만한다.

{
  search(text: "an") {
    __typename
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}

아니면, 아래처럼 공통되는 interface의 field는 이렇게 쓸 수 있다. 단 Starship의 경우 따로이므로 name을 따로 포함해야함

{
  search(text: "an") {
    __typename
    ... on Character {
      name
    }
    ... on Human {
      height
    }
    ... on Droid {
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}

Input types

복잡한 object를 넘기고 싶을 때. Object 타입이랑 똑같이 생겼지만 키워드 input을 사용함. 주로 새로운 데이터를 만들때, 즉 mutation 을 이용할 때 유용하다.

input ReviewInput {
  stars: Int!
  commentary: String
}

쿼리는

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

이런식으로 Input 타입을 넘긴다. 이때 변수는 아래와 같다.

{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}

🤔 오브젝트 타입 정의한 것을 쿼리하기 위해 Input type을 정의할 때 필드를 계속 중복해서 써줘야하나?

GraphQL - Schemas and Types